import * as XLSX from 'xlsx'

export interface ProgressCallback {
  (progress: number, stage: string): void
}

export interface ExcelPreviewResult {
  headers: string[]
  previewData: any[]
}

export interface ExcelStreamResult {
  rowData: any[]
  rowIndex: number
}

export class ExcelReader {
  private static CHUNK_SIZE = 1024 * 1024 // 1MB chunks
  private static PROCESS_BATCH_SIZE = 1000 // 每批处理1000行数据

  // 读取Excel预览（仅读取前6行）
  static async readExcelPreview(file: File): Promise<ExcelPreviewResult> {
    return new Promise((resolve, reject) => {
      const reader = new FileReader()

      reader.onload = async (e) => {
        try {
          if (e.target?.result) {
            const data = e.target.result
            const workbook = XLSX.read(data, { type: 'array' })
            const firstSheetName = workbook.SheetNames[0]
            const worksheet = workbook.Sheets[firstSheetName]

            // 获取表头
            const headers = XLSX.utils.sheet_to_json(worksheet, {
              header: 1,
              range: 0,
              defval: '',
            })[0] as string[]

            // 获取预览数据（前5行）
            const previewRange = {
              s: { r: 1, c: 0 }, // 从第二行开始（跳过表头）
              e: { r: 5, c: headers.length - 1 }, // 读取到第5行
            }

            const previewData = XLSX.utils.sheet_to_json(worksheet, {
              header: 1,
              range: previewRange,
              defval: '',
            })

            resolve({ headers, previewData })
          }
        } catch (error) {
          reject(error)
        }
      }

      reader.onerror = () => {
        reject(new Error('文件读取失败'))
      }

      // 读取文件
      reader.readAsArrayBuffer(file)
    })
  }

  // 流式读取Excel文件
  static async *readExcelStream(
    file: File,
    onProgress: ProgressCallback,
  ): AsyncGenerator<ExcelStreamResult> {
    const reader = new FileReader()
    const chunks: Array<ArrayBuffer> = []
    let offset = 0
    let processedChunks = 0
    const totalChunks = Math.ceil(file.size / this.CHUNK_SIZE)

    // 读取所有chunks
    while (offset < file.size) {
      const chunk = await new Promise<ArrayBuffer>((resolve, reject) => {
        const slice = file.slice(offset, offset + this.CHUNK_SIZE)
        reader.onload = (e) =>
          e.target?.result ? resolve(e.target.result as ArrayBuffer) : reject()
        reader.onerror = () => reject(new Error('文件读取失败'))
        reader.readAsArrayBuffer(slice)
      })

      chunks.push(chunk)
      processedChunks++
      offset += this.CHUNK_SIZE

      // 更新进度
      onProgress(Math.floor((processedChunks / totalChunks) * 50), '正在读取文件...')
    }

    // 合并chunks
    const totalLength = chunks.reduce((acc, chunk) => acc + chunk.byteLength, 0)
    const combinedArray = new Uint8Array(totalLength)
    let pos = 0
    chunks.forEach((chunk) => {
      combinedArray.set(new Uint8Array(chunk), pos)
      pos += chunk.byteLength
    })

    // 解析Excel
    const workbook = XLSX.read(combinedArray, { type: 'array' })
    const firstSheetName = workbook.SheetNames[0]
    const worksheet = workbook.Sheets[firstSheetName]

    // 获取工作表范围
    const range = XLSX.utils.decode_range(worksheet['!ref'] || 'A1')
    const totalRows = range.e.r + 1

    // 逐行处理数据
    for (let rowIndex = 1; rowIndex <= totalRows; rowIndex++) {
      // 读取单行数据
      const rowRange = {
        s: { r: rowIndex, c: 0 },
        e: { r: rowIndex, c: range.e.c },
      }

      const rowData = XLSX.utils.sheet_to_json(worksheet, {
        header: 1,
        range: rowRange,
        defval: '',
      })[0] as any[]

      if (rowData && rowData.length > 0) {
        // 更新进度
        onProgress(50 + Math.floor((rowIndex / totalRows) * 50), '正在处理数据...')

        yield { rowData, rowIndex }

        // 给UI线程一个喘息的机会
        await new Promise((resolve) => setTimeout(resolve, 0))
      }
    }
  }
}
